# -*- coding: utf-8 -*-
from odoo import models, fields, api
from odoo.exceptions import ValidationError
from datetime import date


class Routing(models.Model):
    """工艺流程"""
    _name = 'production.routing'
    _description = '工艺流程'
    _rec_name = 'display_name'
    _order = 'routing_code, routing_operation'
    
    # ==================== 基本信息 ====================
    company_id = fields.Many2one(
        'res.company',
        string='公司',
        default=lambda self: self.env.company,
        required=True,
        help='此工艺流程的唯一公司代码'
    )
    
    routing_code = fields.Char(
        string='工艺流程编码',
        required=True,
        help='此工艺流程的唯一编码'
    )
    
    routing_operation = fields.Integer(
        string='工序号',
        required=True,
        help='工序编号'
    )
    
    routing_description = fields.Char(
        string='工序描述',
        help='生产工序的描述'
    )
    
    active = fields.Boolean(
        string='激活',
        default=True,
        help='是否激活此工艺流程'
    )
    
    # ==================== 工作中心与设备 ====================
    routing_workcenter = fields.Char(
        string='工作中心代码',
        help='执行此工序的工作中心唯一代码'
    )
    
    workcenter_id = fields.Many2one(
        'production.workcenter',
        string='工作中心',
        help='关联的工作中心主数据'
    )
    
    routing_machine = fields.Char(
        string='机器代码',
        help='执行此工序的机器标识代码'
    )
    
    machine_id = fields.Many2one(
        'production.equipment',
        string='机器设备',
        help='关联的机器设备主数据'
    )
    
    routing_mold = fields.Char(
        string='模具代码',
        help='执行此工序使用的模具标识代码'
    )
    
    routing_tool = fields.Char(
        string='工具代码',
        help='此工序使用的工具代码'
    )
    
    # ==================== 时间信息 ====================
    routing_setup = fields.Float(
        string='准备时间(小时)',
        digits=(12, 4),
        default=0.0,
        help='每个订单的标准准备时间（十进制小时）'
    )
    
    routing_run_time = fields.Float(
        string='运行时间(小时)',
        digits=(12, 4),
        default=0.0,
        help='每个零件的标准运行时间（十进制小时）'
    )
    
    routing_move_time = fields.Float(
        string='移动时间(小时)',
        digits=(12, 4),
        default=0.0,
        help='每个订单的标准移动时间（十进制小时）'
    )
    
    # 计算字段
    total_time_per_piece = fields.Float(
        string='单件总时间',
        compute='_compute_total_time',
        store=True,
        help='单个零件的总时间（准备时间+运行时间+移动时间）'
    )
    
    # ==================== 质量信息 ====================
    routing_yield_percent = fields.Float(
        string='良品率(%)',
        digits=(5, 2),
        default=100.0,
        help='此工序预期的合格品质量百分比'
    )
    
    # ==================== 有效期 ====================
    routing_start_date = fields.Date(
        string='生效日期',
        default=fields.Date.today,
        required=True,
        help='此工序成为工艺流程一部分的日期'
    )
    
    routing_end_date = fields.Date(
        string='失效日期',
        help='此工序不再是工艺流程一部分的最后日期'
    )
    
    is_current = fields.Boolean(
        string='当前有效',
        compute='_compute_is_current',
        store=True,
        help='是否在当前日期有效'
    )
    
    # ==================== 关联信息 ====================
    operation_id = fields.Many2one(
        'production.operation',
        string='工序信息',
        help='关联的生产工序主数据'
    )
    
    # ==================== 成本信息 ====================
    setup_cost = fields.Float(
        string='准备成本',
        compute='_compute_costs',
        store=True,
        help='准备成本 = 准备时间 × 工作中心小时成本'
    )
    
    run_cost = fields.Float(
        string='运行成本',
        compute='_compute_costs',
        store=True,
        help='运行成本 = 运行时间 × 工作中心小时成本'
    )
    
    total_cost = fields.Float(
        string='总成本',
        compute='_compute_costs',
        store=True,
        help='总成本 = 准备成本 + 运行成本'
    )
    
    # ==================== 备注 ====================
    notes = fields.Text(
        string='备注',
        help='工艺说明和注意事项'
    )
    
    # ==================== 显示字段 ====================
    display_name = fields.Char(
        string='显示名称',
        compute='_compute_display_name',
        store=True
    )
    
    # ==================== 唯一性约束 ====================
    _sql_constraints = [
        ('routing_unique',
         'UNIQUE(company_id, routing_code, routing_operation, routing_start_date)',
         '工艺流程在同一公司、同一编码、同一工序号和同一生效日期下必须唯一！'),
        ('routing_operation_positive',
         'CHECK(routing_operation > 0)',
         '工序号必须大于0！'),
        ('routing_yield_percent_valid',
         'CHECK(routing_yield_percent >= 0 AND routing_yield_percent <= 100)',
         '良品率必须在0-100之间！'),
    ]
    
    # ==================== 计算方法 ====================
    @api.depends('routing_code', 'routing_operation', 'routing_description')
    def _compute_display_name(self):
        """计算显示名称"""
        for record in self:
            name = f"{record.routing_code} - OP{record.routing_operation:03d}"
            if record.routing_description:
                name += f": {record.routing_description}"
            record.display_name = name
    
    @api.depends('routing_setup', 'routing_run_time', 'routing_move_time')
    def _compute_total_time(self):
        """计算总时间"""
        for record in self:
            record.total_time_per_piece = (
                record.routing_setup + 
                record.routing_run_time + 
                record.routing_move_time
            )
    
    @api.depends('routing_start_date', 'routing_end_date')
    def _compute_is_current(self):
        """计算是否当前有效"""
        today = date.today()
        for record in self:
            is_started = record.routing_start_date <= today if record.routing_start_date else False
            is_not_ended = not record.routing_end_date or record.routing_end_date >= today
            record.is_current = is_started and is_not_ended
    
    @api.depends('routing_setup', 'routing_run_time', 'workcenter_id')
    def _compute_costs(self):
        """计算成本"""
        for record in self:
            hourly_cost = record.workcenter_id.costs_hour if record.workcenter_id else 0.0
            record.setup_cost = record.routing_setup * hourly_cost
            record.run_cost = record.routing_run_time * hourly_cost
            record.total_cost = record.setup_cost + record.run_cost
    
    # ==================== 约束验证 ====================
    @api.constrains('routing_start_date', 'routing_end_date')
    def _check_date_validity(self):
        """验证日期有效性"""
        for record in self:
            if record.routing_end_date and record.routing_start_date > record.routing_end_date:
                raise ValidationError('生效日期不能晚于失效日期！')
    
    # ==================== 字段变更 ====================
    @api.onchange('routing_workcenter')
    def _onchange_routing_workcenter(self):
        """当工作中心代码改变时，尝试关联工作中心主数据"""
        if self.routing_workcenter:
            workcenter = self.env['production.workcenter'].search([
                ('code', '=', self.routing_workcenter),
                ('company_id', '=', self.company_id.id)
            ], limit=1)
            if workcenter:
                self.workcenter_id = workcenter.id
    
    @api.onchange('routing_machine')
    def _onchange_routing_machine(self):
        """当机器代码改变时，尝试关联设备主数据"""
        if self.routing_machine:
            machine = self.env['production.equipment'].search([
                ('equipment_code', '=', self.routing_machine),
                ('company_id', '=', self.company_id.id)
            ], limit=1)
            if machine:
                self.machine_id = machine.id
    
    @api.onchange('routing_operation')
    def _onchange_routing_operation(self):
        """当工序号改变时，尝试关联工序主数据"""
        if self.routing_operation:
            operation = self.env['production.operation'].search([
                ('code', '=', str(self.routing_operation).zfill(3))
            ], limit=1)
            if operation:
                self.operation_id = operation.id
                if operation.workcenter_id:
                    self.workcenter_id = operation.workcenter_id.id
                    self.routing_workcenter = operation.workcenter_id.code
    
    # ==================== 业务方法 ====================
    def get_routing_by_code(self, routing_code, operation_date=None):
        """
        获取指定日期有效的工艺流程
        :param routing_code: 工艺流程编码
        :param operation_date: 工序日期（默认今天）
        :return: routing记录集
        """
        if operation_date is None:
            operation_date = date.today()
        
        domain = [
            ('routing_code', '=', routing_code),
            ('routing_start_date', '<=', operation_date),
            '|',
            ('routing_end_date', '=', False),
            ('routing_end_date', '>=', operation_date),
        ]
        
        return self.search(domain, order='routing_operation')
    
    def calculate_production_time(self, quantity):
        """
        计算生产时间
        :param quantity: 生产数量
        :return: 总时间（小时）
        """
        self.ensure_one()
        total_time = self.routing_setup + (self.routing_run_time * quantity) + self.routing_move_time
        return total_time
    
    def calculate_production_cost(self, quantity):
        """
        计算生产成本
        :param quantity: 生产数量
        :return: 总成本
        """
        self.ensure_one()
        hourly_cost = self.workcenter_id.costs_hour if self.workcenter_id else 0.0
        total_time = self.calculate_production_time(quantity)
        return total_time * hourly_cost
    
    def action_view_related_bom(self):
        """查看使用此工艺流程的BOM"""
        self.ensure_one()
        return {
            'name': f'使用工艺 {self.routing_code} 的BOM',
            'type': 'ir.actions.act_window',
            'res_model': 'bill.of.material',
            'view_mode': 'list,form',
            'domain': [
                ('ps_op', '=', self.routing_operation),
            ],
        }

